package com.tbit.uqbike.client.aop;

import com.tbit.common.utils.TraceUtil;
import com.alibaba.fastjson.JSON;
import com.tbit.common.exceptions.ExternalException;
import com.tbit.uqbike.client.constant.RabbitMQData;
import com.tbit.uqbike.client.dao.log.ThirdExceptionInfoDao;
import com.tbit.uqbike.client.exception.BaseException;
import com.tbit.uqbike.client.pojo.ThirdExceptionInfo;
import com.tbit.uqbike.client.pojo.vo.JsonResult;
import lombok.extern.slf4j.Slf4j;
import com.tbit.uqbike.client.service.MQProducer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
import org.springframework.web.servlet.support.RequestContext;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

/**
 * @Author: chen
 * @Description: 全局异常处理
 * @Date: 创建于 13:38 2021/2/25
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler extends DefaultHandlerExceptionResolver {

//    private final static org.apache.logging.log4j.Logger log = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    @Autowired
    private MQProducer mqProducer;

    /**
     * 自定义异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {BaseException.class})
    @ResponseBody
    public JsonResult handleBaseException(HttpServletRequest request, BaseException e) {
        log.warn("基础异常,接口地址:{},异常信息:{}", request.getRequestURI(), e.getMessage());
        String msg = e.getMessage();
        String traceId = TraceUtil.getTraceIdByLocal();
        if (msg != null && msg.contains("%")) {
            String[] array = msg.split("%");
            RequestContext requestContext = new RequestContext(request);
            String message = requestContext.getMessage(array[1]);
            return JsonResult.fail(array[0], message,traceId);
        } else {
            return JsonResult.fail("-101", e.getMessage(),traceId);
        }

    }

    @ExceptionHandler(value = {BindException.class})
    @ResponseBody
    public JsonResult handlerBindException(HttpServletRequest request,BindException e) {
        log.warn("绑定异常,接口地址:{},参数:{}", request.getRequestURI(), JSON.toJSONString(request.getParameterMap()));
        FieldError fieldError = e.getBindingResult().getFieldError();
        return JsonResult.fail(fieldError.getDefaultMessage(), "绑定异常", TraceUtil.getTraceIdByLocal());
    }

    /**
     * http 请求类型
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {HttpRequestMethodNotSupportedException.class})
    @ResponseBody
    public JsonResult handlerHttpRequestMethodNotSupportedException(HttpServletRequest request,
            HttpRequestMethodNotSupportedException e) {
        log.warn("不支持的http请求类型异常,接口地址:{}",request.getRequestURI(), e);
        return JsonResult.fail("-103", "不支持的http请求类型", TraceUtil.getTraceIdByLocal());
    }

    /**
     * 处理其他异常，记录到日志
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {Exception.class})
    @ResponseBody
    public JsonResult handerOtherException(HttpServletRequest request, Exception e) {
        log.error("服务器异常，接口地址:{},参数:{}", request.getRequestURI(), JSON.toJSONString(request.getParameterMap()), e);
        return JsonResult.fail("-101", "系统繁忙，请稍后再试", TraceUtil.getTraceIdByLocal());
    }

    @ExceptionHandler(value = {MethodArgumentTypeMismatchException.class})
    @ResponseBody
    public JsonResult handerTypeMismatchException(HttpServletRequest request,
                                                  HttpServletResponse response, Object handler, MethodArgumentTypeMismatchException e) {
        String errmsg = "参数转换失败，方法：" + Objects.requireNonNull(e.getParameter().getMethod()).getName()
                + ",期望参数类型：" + e.getParameter().getParameterType()
                + ",参数：" + e.getParameter()
                + ",信息：" + e.getMessage();
        String url = request.getRequestURI();
        log.warn("方法参数不匹配异常，接口地址:{},异常信息:{}", url, errmsg);
        return JsonResult.fail("-101", "错误的参数类型", TraceUtil.getTraceIdByLocal());
    }

    @ExceptionHandler(value = {NumberFormatException.class})
    @ResponseBody
    public JsonResult handerNumberFormatException(HttpServletRequest request,
                                                  HttpServletResponse response, Object handler, NumberFormatException e) {
        log.warn("数字转换异常，接口地址:{},参数:{}", request.getRequestURI(), JSON.toJSONString(request.getParameterMap()), e);
        return JsonResult.fail("-101", "错误的参数类型", TraceUtil.getTraceIdByLocal());
    }

    /**
     * 处理创建订单第三方外部调用错误
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = {ExternalException.class})
    @ResponseBody
    public JsonResult handleExternalException(HttpServletRequest request, ExternalException e) {
        log.error("创建第三方订单异常",e);
        ThirdExceptionInfo exceptionInfo = new ThirdExceptionInfo();
        exceptionInfo.setBrandName(e.getBrandName());
        exceptionInfo.setModel("client");
        exceptionInfo.setPath(request.getRequestURL().toString());
        StackTraceElement[] stackTrace = e.getStackTrace();
        exceptionInfo.setMethod(stackTrace[0].toString());
        exceptionInfo.setParams(JSON.toJSONString(request.getParameterMap()));
        exceptionInfo.setException(e.getExternalExceptionMsg());
        // 执行异步数据库记录，发送MQ消息
        mqProducer.sendToRide(RabbitMQData.queueExchange, RabbitMQData.exceptionKey, JSON.toJSONString(exceptionInfo));
        return JsonResult.fail("-20026", e.getMessage(),TraceUtil.getTraceIdByRequest(request));
    }
}
